#include <iostream>
#include "priority_scheduler.hpp"

using namespace psched;

/*
| Task | Period (ms) | Burst Time (ms) | Priority    |
|------|-------------|-----------------|-------------|
| a    |  250        | 130             | 0 (Lowest)  |
| b    |  500        | 390             | 1           |
| c    | 1000        | 560             | 2 (Highest) |
*/

int main()
{
    PriorityScheduler<
    threads<3>,queues<3,maintain_size<100,discard::oldest_task>>,
    aging_policy<task_starvation_after<std::chrono::milliseconds, 250>, increment_priority_by<1>>>
    scheduler;

    Task a(
        // task action
        [] { std::this_thread::sleep_for(std::chrono::milliseconds(130)); },

        // task post-completion callback
        [](const TaskStats &stats)
        {
            std::cout << "[Task a] ";
            std::cout << "waiting time = " << stats.waiting_time() << "ms; ";
            std::cout << "burst time = " << stats.burst_time() << "ms; ";
            std::cout << "turnaround time = " << stats.turnaround_time() << "ms" << std::endl;
        });

    auto timer_a = std::thread([&scheduler, &a]
    {
        while (true)
        {
            scheduler.schedule<priority<0>>(a);
            std::this_thread::sleep_for(std::chrono::microseconds(250));
        }
    });

    Task b(
        // task action
        [] { std::this_thread::sleep_for(std::chrono::milliseconds(390)); },
        // task post-completion callback
        [](const TaskStats &stats)
        {
            std::cout << "[Task b] ";
            std::cout << "waiting time = " << stats.waiting_time() << "ms; ";
            std::cout << "burst time = " << stats.burst_time() << "ms; ";
            std::cout << "turnaround time = " << stats.turnaround_time() << "ms" << std::endl;
        });
    auto timer_b = std::thread([&scheduler, &b]()
    {
        while (true)
        {
            scheduler.schedule<priority<1>>(b);
            std::this_thread::sleep_for(std::chrono::milliseconds(500));
        }
    });

    Task c(
        // task action
        [] { std::this_thread::sleep_for(std::chrono::milliseconds(500)); },
        // task post-completion callback
        [](const TaskStats &stats)
        {
            std::cout << "[Task c] ";
            std::cout << "waiting time = " << stats.waiting_time() << "ms; ";
            std::cout << "burst time = " << stats.burst_time() << "ms; ";
            std::cout << "turnaround time = " << stats.turnaround_time() << "ms" << std::endl;
        });
    auto timer_c = std::thread([&scheduler, &c]()
    {
        while (true)
        {
            scheduler.schedule<priority<1>>(c);
            std::this_thread::sleep_for(std::chrono::milliseconds(1000));
        }
    });

    timer_a.join();
    timer_b.join();
    timer_c.join();
}